package com.jianbing.lakk.controller;


import com.alibaba.fastjson2.JSONObject;
import com.jianbing.common.annotation.Log;
import com.jianbing.common.core.domain.AjaxResult;
import com.jianbing.common.utils.SecurityUtils;
import javafx.beans.binding.ObjectExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static com.jianbing.common.core.domain.AjaxResult.error;
import static com.jianbing.common.core.domain.AjaxResult.success;

@RestController
@RequestMapping("/memory")
public class ShareMemoryController {



    //设置过期时间 1,800,000（已废止)
    //windbless:过期时间应该设置短一点，然后使用续期的策略，这样可以保证房间的高可用
    private static final Integer PeriodOfValidity = 60000;
    //使用concurrentHashMap保证线程安全 windbless-fixed
    private static final Map<String,Map<String,Map<String,Object>>> shareMemory =   new ConcurrentHashMap<>();
    private static final Logger logger = LoggerFactory.getLogger(ShareMemoryController.class);
    private static final Map<String,String> roomIdAndCreateName = new HashMap<>();
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    // 房间有效期
    private static final Map<String, Date> roomPeriodOfValidity = new HashMap<>();

    @GetMapping("/list")
    public AjaxResult getList(){
        return success(roomIdAndCreateName);
    }

    @PostMapping("/create")
    public AjaxResult createNewShareMemory(){
        String id = SecurityUtils.getUserId().toString();
        if(shareMemory.containsKey(id)){
            return error("已经生成该房间");
        }
        Map<String,Map<String,Object>> newMap = new HashMap<>();
        newMap.put(id,new HashMap<>());
        shareMemory.put(id, newMap);
        roomIdAndCreateName.put(id,SecurityUtils.getUsername());
        roomPeriodOfValidity.put(id,new Date(new Date().getTime()+PeriodOfValidity*10));
        logger.info("房间相关：房间创建,房间号为"+ id +"有效期："+sdf.format(roomPeriodOfValidity.get(id)));
        return success();
    }

    @PostMapping("/add")
    public AjaxResult addNewShareMemory(@RequestBody Map<String,Object> map){
        if(!map.containsKey("key")){
            return error("json中需要包含key");
        }
        String key = (String) map.get("key");
        map.remove("key");
        String userId = SecurityUtils.getUserId().toString();
        if(!shareMemory.containsKey(key)){
            return error("该房间还未创建");
        }
        JSONObject json = new JSONObject(map);
        synchronized (key){
            // TODO 存在值覆盖问题
            if(shareMemory.get(key) == null || shareMemory.get(key).size()==0 ||
                    (shareMemory.get(key).keySet().size()<2 && !shareMemory.get(key).containsKey(userId))){
                shareMemory.get(key).put(userId,map);
                logger.info("房间相关：用户 "+ userId + "  加入房间,房间号为"+ key);
                logger.info("房间相关：房间添加数据,房间号为  "+ key +" 数据 "+json);
            }
            else if(shareMemory.get(key).containsKey(userId)){
                //&& shareMemory.get(key).get(userId)!=null){
                shareMemory.get(key).get(userId).putAll(map);
                logger.info("房间相关：房间添加数据,房间号为  "+ key +" 数据 "+ json);
            }
            else{
                if(shareMemory.get(key).keySet().size()>1){
                    logger.error("房间相关： 用户 "+ userId + " 加入房间失败");
                    return error("该房间已经有两个人");
                }
//                shareMemory.get(key).put(userId,map);
//                logger.info("房间相关：房间添加数据,房间号为  "+ key +" 数据 "+ json);
            }
            roomPeriodOfValidity.put(key,new Date(new Date().getTime()+PeriodOfValidity));
            logger.info("房间相关： 房间有效期更新,房间号为"+ key +"有效期："+sdf.format(roomPeriodOfValidity.get(key)));
        }
        return success();
    }

    @GetMapping("/get")
    public AjaxResult getShareMemory(@RequestParam("key") String key){
        if(!shareMemory.containsKey(key)){
            return error("该房间不存在");
        }
        String userId = SecurityUtils.getUserId().toString();
        synchronized (key){
            //每次查询说明任务有心跳
            roomPeriodOfValidity.put(key,new Date(new Date().getTime()+PeriodOfValidity));
            if(shareMemory.get(key) == null || shareMemory.get(key).size()==0){
                logger.warn("房间相关： 用户"+ userId  + " 访问空房间 "+ key);
                return error("房间未写入内容");
            }
            if(!shareMemory.get(key).containsKey(userId)){
                logger.warn("房间相关： 用户"+ userId  + " 访问未加入的房间 "+ key);
                return error("该用户没有加入该房间");
            }
            for(String secondKey:shareMemory.get(key).keySet()){
                if(!secondKey.equals(userId)){
                    JSONObject json = null;
                    if(shareMemory.get(key).get(secondKey)!=null){
                        json = new JSONObject(shareMemory.get(key).get(secondKey));
                    }
                    logger.info("房间相关： 用户"+ userId  + " 访问房间 "+ key+ " 读取数据 " + json);
                    logger.warn("房间相关： 房间 "+ key + "  删除 用户 " + userId + " 的数据 " );
                    return success(fetchAndClearValue(shareMemory.get(key),secondKey));
                }
            }
        }
        return success();
    }

    @DeleteMapping("/delMsg")
    public AjaxResult deleteShareMemoryMsg(@RequestParam("key") String key,@RequestParam("id") String id){
        for(String secondKey:shareMemory.get(key).keySet()){
            if(!secondKey.equals(id)){
                logger.info("房间相关：用户"+ id +" 删除房间  "+ key  + " 的数据 ");
                shareMemory.get(key).get(secondKey).clear();
            }
        }
        return success();
    }


    @DeleteMapping("/{key}")
    public AjaxResult deleteShareMemory(@PathVariable("key") String key){
        logger.info("房间相关：删除房间  "+ key);
        shareMemory.remove(key);
        roomIdAndCreateName.remove(key);
        return success();
    }

    private static Map<String,Object> fetchAndClearValue(Map<String,Map<String,Object>> map, String key) {
        if(map.get(key) == null){
            return null;
        }
        Map<String,Object> res = new HashMap<>(map.get(key));
        map.get(key).clear();
        return res;
    }

    @Scheduled(fixedRate = 5000)
    private void clearOutOfTimeRoom(){
        logger.info("房间相关：开始清理过期房间");
        List<String> keys = new ArrayList(roomPeriodOfValidity.keySet());
        //输出所有房间及其有效期
        for(String key:keys){
            logger.info("房间相关：房间号为"+key+"的房间，有效期至"+ sdf.format(roomPeriodOfValidity.get(key)));
        }
        for(String key:keys){
            synchronized (key){
                long validityTime = roomPeriodOfValidity.get(key).getTime();
                if(validityTime<new Date().getTime()){
                    logger.warn("【清理】房间号为"+key+"的房间，该房间于"+ sdf.format(roomPeriodOfValidity.get(key))+"过期");
                    roomPeriodOfValidity.remove(key);
                    roomIdAndCreateName.remove(key);
                    shareMemory.remove(key);
                }
            }
        }
    }
}
